/**
 * rainbow.com Inc.
 * Copyright (c) 2014-2015 All Rights Reserved.
 */
package com.rainbow.bam.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.data.jpa.domain.Specification;

/**
 * 
 * 动态SQL拼接
 * 
 * @author HarrisonHan
 * @version $Id: DynamicSpecifications.java, v 0.1 2015年10月26日 上午11:24:35 HarrisonHan Exp $
 */
public class DynamicSpecifications {

    public static <T> Specification<T> bySearchFilter(final Collection<SearchFilter> filters,
                                                      final Class<T> entityClazz) {
        return new Specification<T>() {
            @SuppressWarnings({ "rawtypes", "unchecked" })
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
                                         CriteriaBuilder builder) {
                if (filters != null && filters.size() > 0) {
                    List<Predicate> predicates = new ArrayList<Predicate>();
                    for (SearchFilter filter : filters) {
                        Path expression = root.get(filter.fieldName);
                        // logic operator
                        switch (filter.operator) {
                            case EQ:
                                predicates.add(builder.equal(expression, filter.value));
                                break;
                            case LIKE:
                                predicates.add(builder.like(expression, "%" + filter.value + "%"));
                                break;
                            case GT:
                                predicates.add(builder.greaterThan(expression,
                                    (Comparable) filter.value));
                                break;
                            case LT:
                                predicates.add(builder.lessThan(expression,
                                    (Comparable) filter.value));
                                break;
                            case GTE:
                                predicates.add(builder.greaterThanOrEqualTo(expression,
                                    (Comparable) filter.value));
                                break;
                            case LTE:
                                predicates.add(builder.lessThanOrEqualTo(expression,
                                    (Comparable) filter.value));
                                break;
                        }
                    }
                    // 将所有条件用 and 联合起来
                    if (!predicates.isEmpty()) {
                        return builder.and(predicates.toArray(new Predicate[predicates.size()]));
                    }
                }
                return builder.conjunction();
            }
        };
    }
}
